import java.net.*;
import java.io.*;
import java.util.*;

public class ServerThread extends Thread {
  private Socket socket = null;
  ArrayList<P2PFile> files;
  ArrayList<P2PClient> clients;
  int c;
  P2PClient cli; 

  public ServerThread(Socket socket, ArrayList<P2PFile> files, ArrayList<P2PClient> clients, int c) {
    super("ServerThread");
    this.socket = socket;
    this.files = files;
    this.clients = clients;
    this.c = c;
  }
  
  public void run() {
    try {
      System.out.println("Atendimento do cliente " + socket.getInetAddress().getHostAddress() + " na porta " + socket.getPort());
      String input;
      String[] processedInput;
      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
      int confirmation;
      File f;
      String port;
      int client;

      do {
        input = in.readLine();
        System.out.println("INPUT: "+input);
        processedInput = input.split(" ");
        switch (processedInput[0]) {
          case "new":
            addClient(socket, processedInput[1], processedInput[2], c);
            out.println(Integer.toString(c));
            break;
          case "files":
            out.println(Integer.toString(files.size()));
            synchronized (files) {
              for (int i = 0; i < files.size(); i++) {
                out.println(files.get(i).getFile().getName()+" "+files.get(i).getClient()+" "+files.get(i).getFile().length()+"bytes "+files.get(i).fileAvailable());
              }
            }
            break;
          case "clients":
            out.println(Integer.toString(clients.size()));
            synchronized (clients) {
              for (int i = 0; i < clients.size(); i++) {
                out.println(clients.get(i).getNumber()+" "+clients.get(i).getDir()+" "+clients.get(i).getHost()+" "+clients.get(i).getPort());
              }
            }
            break;
          case "read":
            P2PClient cli = getClient(Integer.parseInt(processedInput[2]));
            if (cli == null) {
              System.out.println("Cliente não existe.");
              out.println("0");
              out.flush();
            } else {
              out.println("1");
              out.flush();
              out.println(cli.getHost());
              out.println(cli.getPort());
            }
            break;
          case "create":
            cli = getClient(Integer.parseInt(processedInput[2]));
            if (cli == null) {
              System.out.println("Cliente não existe.");
              out.println("0");
              out.flush();
            } else {
              out.println("1");
              out.flush();
              out.println(cli.getHost());
              out.println(cli.getPort());
            }
            break;
          case "add":
            f = new File(processedInput[1]);
            client = Integer.parseInt(processedInput[2]);
            addFile(f, client);
            break;
          case "remove":
            cli = getClient(Integer.parseInt(processedInput[2]));
            if (cli == null) {
              System.out.println("Cliente não encontrado.");
              out.println("0");
              out.flush();
            } else {
              P2PFile pf = getFile(processedInput[1], cli.getDir());
              if (pf == null) {
                System.out.println("Arquivo não encontrado.");
                out.println("0");
                out.flush();
              } else {
                if (pf.fileAvailable()) {
                  pf.changeState();
                  out.println("1");
                  out.flush();
                  out.println(cli.getHost());
                  out.println(cli.getPort());
                  if (Integer.parseInt(in.readLine()) == 1) {
                    pf.changeState();
                    synchronized (files) {
                      files.remove(pf);
                    }
                  } else {
                    pf.changeState();
                  }
                } else {
                  System.out.println("Arquivo indisponível.");
                  out.println("0");
                  out.flush();
                }
              }
            }
            break;
          case "exit":
            int numero = Integer.parseInt(in.readLine());
            List<P2PFile> fs = new ArrayList<P2PFile>();
            synchronized (files) {
              for (P2PFile p : files) {
                if (p.getClient() == numero)
                  fs.add(p);
              }
              for (P2PFile p : fs) {
                files.remove(p);
              }
            }
            synchronized (clients) {
              for (P2PClient c : clients) {
                if (c.getNumber() == numero) {
                  clients.remove(c);
                }
              }
            }
            break;
        }
      } while (!input.equals("exit"));
      socket.close();
      System.out.println("connection closed.");
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(-1);
    }
  }

  public void addFile(File file, int client) {
    P2PFile f = new P2PFile(file, client);
    synchronized (files) {
      files.add(f);
    }
  }

  public P2PFile getFile(String file, String dir) {
    synchronized (files) {
      for (P2PFile pf : files) {
        if (("./"+dir+"/"+file).equals(pf.getFile().getPath())) 
          return pf;
      }
    }
    return null;
  }

  public void addClient(Socket socket, String port, String dir, int number) {
    P2PClient cli = new P2PClient(socket.getInetAddress().getHostAddress(), port, dir, number);
    synchronized (clients) {
      clients.add(cli);
    }
  }

  public P2PClient getClient(int number) {
    synchronized (clients) {
      for (P2PClient cli : clients) {
        if (number == cli.getNumber())
          return cli;
      }
    }
    return null;
  }
}